﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace WJP.Queue.Socketing.BufferManagement
{
    struct PoolItemState
    {
        public byte Generation { get; set; }
    }

    /// <summary>
    /// 智能连接池
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class IntelliPool<T> : IntelliPoolBase<T>
    {
        private ConcurrentDictionary<T, PoolItemState> _bufferDict = new ConcurrentDictionary<T, PoolItemState>();
        private ConcurrentDictionary<T, T> _removedItemDict;

        /// <summary>
        /// Initializes a new instance of the <see cref="IntelliPool{T}"/> class.
        /// </summary>
        /// <param name="initialCount">The initial count.</param>
        /// <param name="itemCreator">The item creator.</param>
        /// <param name="itemCleaner">The item cleaner.</param>
        /// <param name="itemPreGet">The item pre get.</param>
        public IntelliPool(int initialCount, IPoolItemCreator<T> itemCreator, Action<T> itemCleaner = null, Action<T> itemPreGet = null)
            : base(initialCount, itemCreator, itemCleaner, itemPreGet)
        {

        }

        /// <summary>
        /// Registers the new item.
        /// </summary>
        /// <param name="item">The item.</param>
        protected override void RegisterNewItem(T item)
        {
            PoolItemState state = new PoolItemState
            {
                Generation = CurrentGeneration
            };
            _bufferDict.TryAdd(item, state);
        }

        /// <summary>
        /// Shrinks this instance.
        /// </summary>
        /// <returns></returns>
        public override bool Shrink()
        {
            var generation = CurrentGeneration;

            if (!base.Shrink())
                return false;

            var toBeRemoved = new List<T>(TotalCount / 2);

            foreach (var item in _bufferDict)
            {
                if (item.Value.Generation == generation)
                {
                    toBeRemoved.Add(item.Key);
                }
            }

            if (_removedItemDict == null)
                _removedItemDict = new ConcurrentDictionary<T, T>();

            foreach (var item in toBeRemoved)
            {
                if (_bufferDict.TryRemove(item, out PoolItemState state))
                    _removedItemDict.TryAdd(item, item);
            }

            return true;
        }

        /// <summary>
        /// Determines whether the specified item can be returned.
        /// </summary>
        /// <param name="item">The item to be returned.</param>
        /// <returns>
        ///   <c>true</c> if the specified item can be returned; otherwise, <c>false</c>.
        /// </returns>
        protected override bool CanReturn(T item)
        {
            return _bufferDict.ContainsKey(item);
        }

        /// <summary>
        /// Tries to remove the specific item
        /// </summary>
        /// <param name="item">The specific item to be removed.</param>
        /// <returns></returns>
        protected override bool TryRemove(T item)
        {
            if (_removedItemDict == null || _removedItemDict.Count == 0)
                return false;

            return _removedItemDict.TryRemove(item, out T removedItem);
        }
    }
}
